#include "uanalyserwidget.h"//
#include "uanalysercontrols.h"
#include "uanalyserrenderer.h"
#include "uanalyserchannel.h"


/*******************************************
 * uAnalyserWidget
 *******************************************/

uAnalyserWidget::uAnalyserWidget(QWidget *parent)
    : QWidget(parent)
{
    mainWindow = qobject_cast<uAnalyserMainWindow*>(parent);

    // Widget construction and property setting
    screenScene = new uAnalyserRenderer(this);
    screenScene->setSceneRect(QRectF()); //return the largest bounding rect of all items on the scene since the scene was created
    screenScene->setItemIndexMethod(QGraphicsScene::NoIndex);
    screenView = new QGraphicsView(screenScene);

    screenView->setRenderHint(QPainter::NonCosmeticDefaultPen);//QPainter::Antialiasing);
    screenView->setBackgroundBrush(QBrush(Qt::white));
    screenView->setCacheMode(QGraphicsView::CacheBackground);
    screenView->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);

    operatorPanel = new uAnalyserControls(this);

    // Layouting
    QHBoxLayout *viewLayout = new QHBoxLayout();
    setLayout(viewLayout);
    viewLayout->addWidget(screenView,1);
    viewLayout->addWidget(operatorPanel,0);

    //some default time base for test purposes
    for (double ti=0; ti<10; ti+=(double)10/(double)800)
        timeSweep << ti;

    screenScene->update();
    mode = SvgViewerMode;
}

uAnalyserWidget::~uAnalyserWidget()
{
 while (!channels.isEmpty())
     delete channels.takeFirst();

}

double uAnalyserWidget::getTimeBase()
{
    return timeBase;
}

uAnalyserChannel* uAnalyserWidget::addNewChannel(bool generateExampleWave)
{
    mode = SvgViewerMode;
    uAnalyserChannel *temp = new uAnalyserChannel( operatorPanel, this, screenScene, &timeSweep );
    const int samples_num = timeSweep.size();
    temp->voltage.clear();
    if (generateExampleWave)
        {
        const double period_min = (timeSweep.at(timeSweep.size()-1) - timeSweep.at(0)) * 0.2;
        const double period_max = (timeSweep.at(timeSweep.size()-1) - timeSweep.at(0)) * 0.8;
        const double init_phase = (double)(rand()%1000)/(double)1000; //in 0-1 range
        const double amp = 0.4+2*((double)(rand()%100))/(double)100; //0.4 - 2.4 range
        const double period = period_min+(double)(rand()%1000)*(period_max-period_min)/1000.0;
        for (int i=0; i<samples_num; ++i)
            temp->voltage << amp*sin((timeSweep.at(i)/period+init_phase)*2*3.1416);
        }
    else
        temp->voltage.fill(0,samples_num);

    temp->recalculateTrace();

    channels << temp;
    operatorPanel->channelControlsLayout->addWidget(temp->channelGroupBox);
    screenScene->update();
    return temp;
}

uAnalyserChannel* uAnalyserWidget::addNewChannel(QVector<double> &v)
{
    uAnalyserChannel *temp = new uAnalyserChannel( operatorPanel, this, screenScene, &timeSweep );
    temp->voltage = v;
    temp->recalculateTrace();
    channels << temp;
    operatorPanel->channelControlsLayout->addWidget(temp->channelGroupBox);
    screenScene->update();
    return temp;
}

void uAnalyserWidget::removeChannel()
{
    uAnalyserChannel* temp = qobject_cast<uAnalyserChannel*>(QObject::sender());
    operatorPanel->channelControlsLayout->removeWidget(temp->channelGroupBox);
    channels.removeOne(temp);
    delete temp;
    screenScene->update();
}

void uAnalyserWidget::refreshChannels()
{
    foreach(uAnalyserChannel* chan, channels)
        chan->recalculateTrace();
    screenScene->update();
}

//In input CSV file, first column has to be a timestamp, and following columns have to be signal values(see example.csv)
void uAnalyserWidget::loadCsvFile(){
    QString csvFileName = QFileDialog::getOpenFileName(this,
        tr("Open Trace"), "",
        tr("Trace file(*.csv);; All Files(*)"));

    if (csvFileName.isEmpty())
        return;
    else {
        QFile csvFile(csvFileName);

        if (!csvFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QMessageBox::information(this, tr("Unable to open file"),
                csvFile.errorString());
            return;
            }

        closeOscilloscope();
        mode = SvgViewerMode;
        //remove old channel that previously could be created
        //because opened file probably uses different time sweep
        uAnalyserChannel* old_channel;
        while (!channels.isEmpty()) {
            old_channel = channels.takeFirst();
            operatorPanel->channelControlsLayout->removeWidget(old_channel->channelGroupBox);
            channels.removeOne(old_channel);
            delete old_channel;
            }

        //prepare text stream for operations
        QTextStream csvStream(&csvFile);
        csvStream.setNumberFlags ( QTextStream::ForcePoint );
        csvStream.setRealNumberNotation ( QTextStream::SmartNotation );
        csvStream.setLocale ( QLocale::C );

        //determine number of columns in opened csv file
        double temp;
        int channels_num;
        csvStream.skipWhiteSpace();
        {
        QString temp_string = csvStream.readLine();
        QTextStream temp_stream(&temp_string);
        for(channels_num=0; !temp_stream.atEnd(); channels_num++)
            temp_stream >> temp;
        channels_num--; //first "channel" is timeSweep
        }

        //read and "parse" whole file
        timeSweep.clear();
        QVector<double> channel[channels_num];
        csvStream.seek(0);
        csvStream.skipWhiteSpace();
        while (!csvStream.atEnd()) {
            csvStream >> temp;
            timeSweep << temp;
            for (int i=0; i<channels_num; i++){
                csvStream >> temp;
                channel[i] << temp;
                }
            csvStream.skipWhiteSpace();
            }

        //create all channels with data from opened file
        for (int i=0; i<channels_num; i++)
            addNewChannel(channel[i]);
        operatorPanel->adjustTimeBase(timeSweep.last()-timeSweep.first());
        screenScene->update();
        csvFile.close();
        }
};

void uAnalyserWidget::saveSvgFile(){

    QString svgPath = QFileDialog::getSaveFileName(this, tr("Save SVG"),
        QString(), tr("SVG files (*.svg)"));

//![configure SVG generator]
    QSvgGenerator generator;
    generator.setFileName(svgPath);
    generator.setSize(screenView->sizeHint());
    generator.setViewBox(screenView->sceneRect());
    generator.setTitle(tr("uAnalyser screen output"));
    generator.setDescription(tr("Time Base = X s/div; Channel 1 Y Gain = Y V/div; Channel 2 Y Gain = Z V/div "));
    QPainter painter;
    painter.begin(&generator);
    screenView->render(&painter);
    painter.end();

}

void uAnalyserWidget::openOscilloscope(){
    if (mode != OscilloscopeMode)
        {
        //remove old channel that previously could be created
        //because opened file probably uses different time sweep
        uAnalyserChannel* old_channel;
        while (!channels.isEmpty())
            {
            old_channel = channels.takeFirst();
            operatorPanel->channelControlsLayout->removeWidget(old_channel->channelGroupBox);
            channels.removeOne(old_channel);
            delete old_channel;
            }

        oscilloscopeSampleRate = 22050;
        oscilloscopeBufferSize = 1000;
        timeSweep.clear();
        for (int i=0; i<oscilloscopeBufferSize; i++)
            timeSweep << (double)i/(double)oscilloscopeSampleRate;
        uAnalyserChannel* temp = addNewChannel(false); //add new channel for audio
        operatorPanel->adjustTimeBase(timeSweep.last()-timeSweep.first());
        audioInput = new uAnalyserAudioInput;
        connect(audioInput, SIGNAL(audioBufferRefreshed()), this, SLOT(refreshChannels()));
        audioInput->startRecording(oscilloscopeSampleRate, oscilloscopeBufferSize, &(temp->voltage));
        operatorPanel->showTriggerControls(true);
        mainWindow->newChannelEnable(false); //disable adding test channels
        screenScene->update();
        mode = OscilloscopeMode;
        }
}

//void uAnalyserWidget::pauseOscilloscope(bool p){
//    audioInput->pauseRecording(p);
//}

void uAnalyserWidget::closeOscilloscope(){
    if (mode == OscilloscopeMode)
        {
        //delete oscilloscope channels
        uAnalyserChannel* old_channel;
        while (!channels.isEmpty())
            {
            old_channel = channels.takeFirst();
            operatorPanel->channelControlsLayout->removeWidget(old_channel->channelGroupBox);
            channels.removeOne(old_channel);
            delete old_channel;
            }
        delete audioInput;
        mainWindow->newChannelEnable(true);
        operatorPanel->showTriggerControls(false);
        mode = SvgViewerMode;
        }
}

void uAnalyserWidget::setTimeBase(double time_base)
{
    timeBase = time_base;
    foreach (uAnalyserChannel *channel, channels)
        channel->setTimeBase(time_base);
    screenScene->update();
}

void uAnalyserWidget::showAxes(int state)
{
    if (state==Qt::Unchecked)
        screenScene->setAxesVisible(false);
    else
        screenScene->setAxesVisible(true);
}

void uAnalyserWidget::showGrid(int state)
{
    if (state==Qt::Unchecked)
        screenScene->setGridVisible(false);
    else
        screenScene->setGridVisible(true);
}


/*******************************************
 * uAnalyserMainWindow
 *******************************************/

uAnalyserMainWindow::uAnalyserMainWindow()
{
    mainWidget = new uAnalyserWidget(this);
    setCentralWidget(mainWidget);
    createActions();
    createMenus();
    setWindowTitle(tr("uAnalyser"));
}

//void uAnalyserMainWindow::newChannelEnable(bool flag)
//{
//    newChannelAct->setEnabled(flag);
//}

void uAnalyserMainWindow::createActions()
{
    newChannelAct = new QAction(tr("Add new channel"), this);
    connect(newChannelAct, SIGNAL(triggered()), mainWidget, SLOT(addNewTestChannel()));
    loadCsvAct = new QAction(tr("Load CSV file"), this);
    connect(loadCsvAct, SIGNAL(triggered()), mainWidget, SLOT(loadCsvFile()));
    saveSvgAct = new QAction(tr("Save SVG file"), this);
    connect(saveSvgAct, SIGNAL(triggered()), mainWidget, SLOT(saveSvgFile()));
    oscilloscopeAct = new QAction(tr("Start oscilloscope"), this);
    connect(oscilloscopeAct, SIGNAL(triggered()), mainWidget, SLOT(openOscilloscope()));
    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setShortcuts(QKeySequence::Quit);
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
}

void uAnalyserMainWindow::createMenus()
{
//    QMenu *fileMenu;
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(newChannelAct);
    fileMenu->addAction(loadCsvAct);
    fileMenu->addAction(saveSvgAct);
    fileMenu->addAction(oscilloscopeAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

}





